/*
 * Copyright (C) 2010 M. Hautle.
 * 
 * This file is part of TrackedBean.
 * 
 * TrackedBean is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option) any later version.
 * 
 * TrackedBean is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License along with TrackedBean. If not, see <http://www.gnu.org/licenses/>.
 */
package ch.trackedbean.internal;

import java.util.*;
import org.osgi.framework.*;
import org.osgi.util.tracker.*;
import ch.trackedbean.loaders.internal.*;

/**
 * OSGi service tracker for the {@link LoaderList}s.<br>
 * Creates simply a {@link ServiceTracker} which calls {@link LoaderList#registerService(ILoaderService)} and
 * {@link LoaderList#unregisterService(Class, boolean)}.
 * 
 * @author M. Hautle
 * @since 17.10.2010
 */
public class LoaderListSericeTracker {
    /** The registered trackers. */
    private static final List<LoaderTracker> TRACKERS = new ArrayList<LoaderTracker>();

    /** The bundle context or null if not started. */
    private static BundleContext ctx;

    /**
     * Registers the given {@link LoaderList} on the specified {@link ILoaderService} type.
     * 
     * @param <T> The {@link ILoaderService} type
     * @param list The list
     * @param type The {@link ILoaderService} type
     */
    public static synchronized <T extends ILoaderService> void register(LoaderList<T> list, Class<T> type) {
        final LoaderTracker<T> t = new LoaderTracker<T>(list, type);
        if (ctx != null)
            t.start();
        TRACKERS.add(t);
    }

    /**
     * Method 'activating' the tracker - must be called by the bundle activator.
     * 
     * @param ctx The bundle context
     */
    public static synchronized void start(BundleContext ctx) {
        LoaderListSericeTracker.ctx = ctx;
        for (LoaderTracker t : TRACKERS)
            t.start();
    }

    /**
     * Method stopping the tracker - must be called by the bundle activator.
     */
    public static synchronized void stop() {
        ctx = null;
        for (LoaderTracker t : TRACKERS)
            t.stop();
    }

    /**
     * {@link ServiceTrackerCustomizer} adding and removing the services from a {@link LoaderList}.
     * 
     * @param <T> The {@link ILoaderService} used in the tracked list
     * @author M. Hautle
     * @since 17.10.2010
     */
    private static class LoaderTracker<T extends ILoaderService> implements ServiceTrackerCustomizer {
        /** The list to work on. */
        private final LoaderList<T> list;

        /** The {@link ILoaderService} type contained in the {@link #list}. */
        private final Class type;

        /** The current service tracker or null if not tracking. */
        private ServiceTracker tracker;

        /**
         * Default constructor.
         * 
         * @param list The list
         * @param type The {@link ILoaderService} subtype to look for
         */
        public LoaderTracker(LoaderList<T> list, Class<T> type) {
            this.list = list;
            this.type = type;
        }

        /**
         * Starts the {@link ServiceTracker}.
         */
        public void start() {
            tracker = new ServiceTracker(ctx, type.getName(), this);
            tracker.open(true);
        }

        /**
         * Stops the {@link ServiceTracker} and clears the {@link LoaderList}.
         */
        public void stop() {
            if (tracker != null)
                tracker.close();
            tracker = null;
            list.clear();
        }

        /**
         * {@inheritDoc}
         */
        @Override
        @SuppressWarnings("unchecked")
        public Object addingService(ServiceReference reference) {
            final Object srv = ctx.getService(reference);
            list.registerService((T) srv);
            return srv;
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public void modifiedService(ServiceReference reference, Object service) {
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public void removedService(ServiceReference reference, Object service) {
            final ILoaderService srv = (ILoaderService) service;
            list.unregisterService(srv.getType(), srv.isSuperLoader());
        }
    }
}
